/*
 * @(#)SolrHandler.java 2014-12-19 上午11:40:08
 * Copyright 2014 鲍建明, Inc. All rights reserved. 8637.com
 * PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package com.myschool.solr.handler;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.ConcurrentUpdateSolrServer;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.apache.solr.client.solrj.impl.LBHttpSolrServer;
import org.apache.solr.client.solrj.request.AbstractUpdateRequest;
import org.apache.solr.client.solrj.request.ContentStreamUpdateRequest;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;

import com.myschool.solr.bean.Highilight;
import com.myschool.solr.bean.Page;
import com.myschool.solr.bean.PageResult;
import com.myschool.solr.bean.Sort;
import com.myschool.solr.query.QueryBean;
import com.myschool.solr.utils.SolrUtils;


/**
 * 1、ConcurrentUpdateSolrServer实例化SolrServer，该类实例化多用于更新删除索引操作
ConcurrentUpdateSolrServer(String solrServerUrl,  int queueSize,  int threadCount)
solrServerUrl是Solr服务器的地址，
queueSize缓冲区大小
threadCount 后台线程数
其需要与 autoCommit 、 autoSoftCommit 配置搭配使用
<autoCommit>

                 <maxTime>100000(1-10min)</maxTime>

                 <openSearcher>false</openSearcher>

</autoCommit>

<autoSoftCommit>

        <maxTime>1000(1s)</maxTime>

</autoSoftCommit>



2、HttpSolrServer 实例化SolrServer，该类实例化多用于查询操作
HttpSolrServer(String baseURL)
baseURL是Solr的服务器地址
3、LBHttpSolrServer实例化SolrServer，用于有多个Solr服务器，负载均衡
LBHttpSolrServer(String... solrServerUrls)
　　solrServerUrls是多个Solr的服务器地址，用,号分隔
 */

/**
 * <p>File：SolrHandler.java</p>
 * <p>Title: </p>
 * <p>Description:</p>
 * <p>Copyright: Copyright (c) 2014 2014-12-19 上午11:40:08</p>
 * <p>Company: 8637.com</p>
 * @author 鲍建明
 * @version 1.0
 */
public class SolrHandler
{
	
	private static final String URL = "http://localhost:8082";
	//private SolrServer server = new HttpSolrServer(URL + "/solr/bean");  
	
	private Integer flush = 100;
	
	private SolrServer server;
	
	private String URI ;
	
	private String indexDatabase;
	
	/**
	 * 是否是多个solr服务器，负载均衡  默认不是
	 */
	private Boolean equilibrium = false;
	
	public SolrHandler(String URI, String IndexDatabase){
		this.URI = URI;
		this.indexDatabase = IndexDatabase;
	}
	

	/**
	 * 以对象的创建
	 * @param beans
	 * @throws IOException 
	 * @throws SolrServerException 
	 */
	public void addByBean(List<?> beans) throws Exception{
		//org.apache.solr.client.solrj.util.ClientUtils. 该类中有过滤字符串的方法可以使用
		getSolrServer(ServerType.OPERATE).addBeans(beans);
		SolrUtils.commit(server);
	}
	
	/**
	 * 单个对象的创建
	 * @param bean
	 * @throws SolrServerException 
	 * @throws IOException 
	 */
	public void addByBean(Object bean) throws Exception{
		getSolrServer(ServerType.OPERATE).addBean(bean);
		SolrUtils.commit(server);
	}
	
	
	/**
	 * 以lucene 的document方式创建索引对象
	 * 不是很推荐使用，最好以对象的形式去操作，因为二者底层的操作方式是一致的
	 * @param params
	 * @throws Exception
	 */
	public void addByDocument(Map<String, Object> params) throws Exception{
		SolrInputDocument doc = new SolrInputDocument(); 
		for (Entry<String, Object> param : params.entrySet())
		{
			doc.addField(param.getKey(), param.getValue());
		}
		getSolrServer(ServerType.OPERATE).add(doc);
		SolrUtils.commit(server);
	}
	
	
	
	/**
	 * 删除索引
	 * @param id
	 * @throws Exception
	 */
	public void deleteById(String id) throws Exception{
		getSolrServer(ServerType.OPERATE).deleteById(id);
		SolrUtils.commit(server);
	} 
	
	/**
	 * 删除索引
	 * @param ids
	 */
	public void deleteById(List<String> ids) throws Exception{
		getSolrServer(ServerType.OPERATE).deleteById(ids);
		SolrUtils.commit(server);
	}
	
	/**
	 * 修改
	 * @param id
	 * @param bean
	 * @throws Exception
	 */
	public void update(String id, Object bean) throws Exception{
		getSolrServer(ServerType.OPERATE).deleteById(id);
		server.addBean(bean);
		SolrUtils.commit(server);
	}
	
	
	
	/**
	 * 查询
	 * @param queryBean
	 * @return
	 * @throws Exception
	 */
	public <T> PageResult<T> queryResult(QueryBean queryBean) throws Exception{
		SolrQuery q = setSolrQuery(queryBean);
		QueryResponse response = getSolrServer(ServerType.QUERY).query(q);
		SolrDocumentList solrDocumentList = response.getResults();
		queryBean.getPage().setRowSize(solrDocumentList.getNumFound());
		return new PageResult(queryBean.getPage(), response.getBeans(queryBean.getType()), response.getHighlighting(), response);
	}
	
	
	
	
	/**************************************************** private **********************************************************************/
	
	/**
	 * 设置SolrQuery查询参数
	 * @param queryBean
	 * @return
	 */
	private SolrQuery setSolrQuery(QueryBean queryBean){
		setPage(queryBean.getQ(), queryBean.getPage());
		setHighlight(queryBean.getQ(), queryBean.getHighilight());
		return queryBean.getQ();
	}
	
	/**
	 * 设置查询高亮
	 * @param q
	 * @param highilight
	 * @return
	 */
	private SolrQuery setHighlight(SolrQuery query, Highilight highilight){
		if( highilight.getIsHighilight() ){
			query.setHighlight(true);					//开启高亮组件
			for (String field : highilight.getFields())
			{
				query.addHighlightField(field);			//添加 高亮字段
			}
			query.setHighlightSimplePre(highilight.getPrefix());		//标记，高亮关键字前缀
			query.setHighlightSimplePost(highilight.getSuffix());		//后缀	
			query.setHighlightSnippets(2);//结果分片数，默认为1
			query.setHighlightFragsize(1000);//每个分片的最大长度，默认为100
		}
		return query;
	}
	
	/**
	 * 设置分页和排序
	 * @param q
	 * @param page
	 * @return
	 */
	private SolrQuery setPage(SolrQuery query, Page page){
		query.setStart( (page.getPageNow() - 1) * page.getPageSize() );
		query.setRows(page.getPageSize());
		 List<Sort> sorts =  page.getSorts();
		 if(sorts != null && sorts.size() > 0){
			for (Sort sort : sorts)
			{
				query.setSort(sort.getField(), sort.getOrder());
			}
		 }
		 return query;
	}
	
	
	/**
	 * 获取Solr服务
	 * @param type
	 * @return
	 * @throws MalformedURLException
	 */
	private SolrServer getSolrServer(ServerType type) throws MalformedURLException{
		String url = this.URI + this.indexDatabase;
		if(equilibrium){				//负载均衡
			return new LBHttpSolrServer(url);
		}
		switch (type)
		{
		case QUERY:
			this.server =  new HttpSolrServer(url);
			break;
		case OPERATE:
			this.server =  new ConcurrentUpdateSolrServer(url, 1024 * 1024 * 50, 3);				//参数请更具实际情况设置
		default:
			this.server = new HttpSolrServer(url); 
		}
		return this.server;
	}
	
	
	/**
	 * 以文件形式创建索引
	 * @param file
	 * @param contentType
	 * @param solrId
	 * @throws Exception
	 */
	public void addByFile(File file, String contentType, String solrId) throws Exception{
		ContentStreamUpdateRequest up = new ContentStreamUpdateRequest("/update/file");			//在指定索引库中对应的中修改solrconfig.xml文件， 提供支持上传文件请求头
		up.addFile(file, contentType);
		up.setParam("literal.id", solrId);
		up.setParam("uprefix", "attr_");  
		up.setParam("fmap.content", "attr_content");  
		up.setAction(AbstractUpdateRequest.ACTION.COMMIT, true, true);
		server.request(up);
		//QueryResponse rsp = solr.query(new SolrQuery("*:*"));  
        //System.out.println(rsp); 
	}
	

	
	
	
	
	enum ServerType {
		/**
		 * 查询
		 */
		QUERY,
		/**
		 * 增，删，改
		 */
		OPERATE
	}
	
	
	public void setEquilibrium(Boolean equilibrium)
	{
		this.equilibrium = equilibrium;
	}

	public void setFlush(Integer flush)
	{
		this.flush = flush;
	}


	public void setIndexDatabase(String indexDatabase)
	{
		this.indexDatabase = indexDatabase;
	}
	
}
